package com.yedean.mall.token;

import com.alibaba.fastjson.JSON;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;

/**
 * TokenRedisAccessor
 *
 * @author yedean
 * @date 2022/8/17
 */
public class TokenRedisAccessor {

    private final RedisTemplate<String, Object> redisTemplate;

    private final String namespace;

    public static final String NAMESPACE_SEPARATOR = ":";

    public static final String ACCESS_SECTION = "A";

    public static final String REFRESH_SECTION = "R";

    public static final String LOGIN_SECTION = "N";

    public static final String DELETE_USER_SECTION = "D";


    public TokenRedisAccessor(RedisTemplate<String, Object> redisTemplate, String namespace) {
        this.redisTemplate = redisTemplate;
        this.namespace = namespace;
    }

    /**
     * 插入redis AccessToken
     */
    public boolean insertAccessToken(AccessTokenEntity entity) {
        String userInfo = JSON.toJSONString(entity.getUserInfo());
        String key = inAccessNamespace(entity.getAccessToken());
        Boolean success = redisTemplate.opsForHash().putIfAbsent(key, AccessTokenEntity.USER_INFO_KEY, userInfo);
        if (!success) {
            return false;
        }
        redisTemplate.opsForHash().put(key, AccessTokenEntity.REFRESH_TOKEN_KEY, entity.getRefreshToken());
        redisTemplate.expireAt(key, entity.getExpireIn());
        return true;
    }

    /**
     * 删除accessToken
     */
    public void deleteAccessToken(String accessToken) {
        redisTemplate.delete(inAccessNamespace(accessToken));
    }


    /**
     * 删除RefreshToken
     */
    public void deleteRefreshToken(String refreshToken) {
        redisTemplate.delete(inRefreshNamespace(refreshToken));
    }


    /**
     * 查询accessToken信息
     */
    public AccessTokenEntity selectAccessToken(String accessToken) {
        String key = inAccessNamespace(accessToken);
        String refreshToken = (String) redisTemplate.opsForHash().get(key, AccessTokenEntity.REFRESH_TOKEN_KEY);
        if (refreshToken == null) {
            return null;
        }
        String json = (String) redisTemplate.opsForHash().get(key, AccessTokenEntity.USER_INFO_KEY);

        UserInfo userInfo = JSON.parseObject(json, UserInfo.class);

        return new AccessTokenEntity(accessToken, refreshToken, userInfo);
    }


    public void updateAccessToken(AccessTokenEntity entity) {
        String key = inAccessNamespace(entity.getAccessToken());
        Boolean res = redisTemplate.hasKey(key);
        boolean exists = res != null && res;
        if (!exists) {
            return;
        }

        BoundHashOperations<String, String, String> ops = redisTemplate.boundHashOps(key);
        if (entity.getRefreshToken() != null) {
            ops.put(AccessTokenEntity.REFRESH_TOKEN_KEY, entity.getRefreshToken());
        }

        if (entity.getUserInfo() != null) {
            String json = JSON.toJSONString(entity.getUserInfo());
            ops.put(AccessTokenEntity.USER_INFO_KEY, json);
        }
    }


    public boolean insertRefreshToken(RefreshTokenEntity entity) {
        String json = JSON.toJSONString(entity.getUserInfo());

        String key = inRefreshNamespace(entity.getRefreshToken());

        boolean success = redisTemplate.opsForHash().putIfAbsent(key, RefreshTokenEntity.ACCESS_TOKEN_KEY, entity.getAccessToken());

        if (!success) {
            return false;
        }
        redisTemplate.opsForHash().put(key, RefreshTokenEntity.USER_INFO_KEY, json);
        redisTemplate.expireAt(key, entity.getExpireIn());
        return true;
    }

    public void updateRefreshToken(RefreshTokenEntity entity) {
        String key = inRefreshNamespace(entity.getRefreshToken());
        Boolean res = redisTemplate.hasKey(key);
        boolean exists = res != null && res;
        if (!exists) {
            return;
        }

        BoundHashOperations<String, String, String> ops = redisTemplate.boundHashOps(key);
        if (entity.getAccessToken() != null) {
            ops.put(RefreshTokenEntity.ACCESS_TOKEN_KEY, entity.getAccessToken());
        }

        if (entity.getUserInfo() != null) {
            String json = JSON.toJSONString(entity.getUserInfo());
            ops.put(RefreshTokenEntity.USER_INFO_KEY, json);
        }
    }

    public RefreshTokenEntity selectRefreshToken(String refreshToken) {
        String key = inRefreshNamespace(refreshToken);
        String accessToken = (String) redisTemplate.opsForHash().get(key, RefreshTokenEntity.ACCESS_TOKEN_KEY);
        if (accessToken == null) {
            return null;
        }
        String json = (String) redisTemplate.opsForHash().get(key, RefreshTokenEntity.USER_INFO_KEY);
        if (json == null) {
            return null;
        }
        UserInfo userInfo = JSON.parseObject(json, UserInfo.class);

        return new RefreshTokenEntity(refreshToken, accessToken, userInfo);
    }


    /**
     * access_token的命名空间
     */
    private String inAccessNamespace(String key) {
        return this.namespace + NAMESPACE_SEPARATOR + ACCESS_SECTION + NAMESPACE_SEPARATOR + key;
    }

    /**
     * refresh_token的命名空间
     */
    private String inRefreshNamespace(String key) {
        return this.namespace + NAMESPACE_SEPARATOR + REFRESH_SECTION + NAMESPACE_SEPARATOR + key;
    }
}
